/* 
Scenic Graphics Library
Copyright (C) 2007 Jouni Tulkki

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USApackage scenic;
*/

package scenic.toolkit.text;

import java.util.Vector;

import scenic.toolkit.CComponent;

public class ParagraphIterator {
	private double frameWidth;
	
	private Vector<ElementItem> objects = new Vector<ElementItem>();
	
	private CParagraph paragraph;
	private Element element;
	private int elementIndex;
	private int itemIndex;

	private double top;
	private double maxAscent;
	private double maxDescent;
	private double totalWidth;
	
	private int lineEnd;
	private boolean lineIsFull;

	public ParagraphIterator(CParagraph paragraph, double frameWidth) {
		this.paragraph = paragraph;
		this.frameWidth = frameWidth;
		if(paragraph.getElements().size() > 0) {
			element = paragraph.getElements().elementAt(0);
		}
	}

	public boolean hasNext() {
		if(lineEnd == 0) {
			processNextLine();
		}
		return lineEnd > 0;
	}
	
	public ElementItem next() {
		if(lineEnd == 0) {
			processNextLine();
		}
		lineEnd--;
		return objects.remove(0);
	}
	
	public double getLineTop() {
		return top;
	}
	
	private ElementItem getNextObject() {
		if(element == null) {
			return null;
		}
		ElementItem object = element.getItemInfo(itemIndex++, null);
		if(itemIndex >= element.getNumItems()) {
			Vector<Element> elements = paragraph.getElements();
			
			elementIndex++;
			if(elementIndex >= elements.size()) {
				element = null;
			} else {
				element = elements.elementAt(elementIndex);
				itemIndex = 0;
			}
		}
		return object;
	}
	
	public boolean processObject(ElementItem object) {
		if(totalWidth + object.width > frameWidth && lineEnd > 0 && !object.isSpace) {
			lineIsFull = true;
			return true;
		}
		maxAscent = Math.max(maxAscent, object.ascent);
		maxDescent = Math.max(maxDescent, object.descent);
		totalWidth += object.width;
		lineEnd++;
		return false;
	}
	
	private void calcAscentAndDescent(int end) {
		maxAscent = 0;
		maxDescent = 0;
		for(int i = 0; i < end; i++) {
			maxAscent = Math.max(maxAscent, objects.elementAt(i).ascent);
			maxDescent = Math.max(maxDescent, objects.elementAt(i).descent);
		}
	}
	
	private void processNextLine() {
		getObjectsForLine();
		layoutLine();
	}
	
	private void getObjectsForLine() {
		ElementItem object;
		
		top += maxAscent + maxDescent;
		maxAscent = 0;
		maxDescent = 0;	
		totalWidth = 0;
		lineIsFull = false;
		lineEnd = 0;
		
		for(int i = 0; i < objects.size(); i++) {
			processObject(objects.elementAt(i));
			if(lineIsFull)
				return;
		}
		do {
			object = getNextObject();
			
			if(object == null)
				return;
			objects.add(object);
			processObject(object);
		} while(!lineIsFull);
	}
	
	private void layoutLine() {
		int layoutEnd = lineEnd;
			
		if(lineIsFull) {
			for(int i = lineEnd - 1; i > 0; i--) {
				if(objects.elementAt(i).isSpace) {
					while(i > 1 && objects.elementAt(i - 1).isSpace)
						i--;
					lineEnd = i + 1;
					layoutEnd = i;
					break;
				}
			}
		}

		calcAscentAndDescent(layoutEnd);
		
		double x = 0;
		
		for(int i = 0; i < lineEnd; i++) {
			objects.elementAt(i).x = x;
			objects.elementAt(i).y = top + maxAscent;
			x += objects.elementAt(i).width;
		}
	}
}
